import { PaginationProps } from "ant-design-vue";
import { ref, watch } from "vue";
import {
    RouteLocationNormalizedLoaded,
    Router,
    stringifyQuery,
} from "vue-router";
import { ILazyTableService, LazyTable, LazyTableService } from "./types";
import { message } from "ant-design-vue";
import dayjs from "dayjs";
import usePresetDatePicker from "../usePresetDatePicker/usePresetDatePicker";

export type DateRangeFieldNames = { startTime: string; endTime: string } | null;

export function useLazyLable<T = any>(
    router: Router,
    route: RouteLocationNormalizedLoaded,
    service: T extends ILazyTableService ? T : any,
    paginationOption: PaginationProps = {
        pageSize: 12,
    },
    queryType = "string",
    immediate = true,
    dateRangeFieldNames: DateRangeFieldNames = {
        startTime: "startTime",
        endTime: "endTime",
    },
    queryValueTypeMap: any = {},
    customSearch?: (args: any) => void,
) {
    const presets = usePresetDatePicker();
    const searchObj = ref<any>({});
    const queryObj = ref<any>({});

    type ServiceGetListReturn = ReturnType<(typeof service)["getList"]>;
    type UnpackPromise<T> = T extends Promise<infer U> ? U : T;
    type Res = UnpackPromise<ServiceGetListReturn>["data"]["result"]["data"];
    type ResData = Res extends Array<any> ? Res[0] : Res;

    const lazyTable = ref(new LazyTable<ResData>(undefined, paginationOption));
    const getList = async () => {
        lazyTable.value.loading = true;
        queryObj.value.current_page = lazyTable.value.pagination.current;
        queryObj.value.page_items = lazyTable.value.pagination.pageSize;
        let query: any;
        if (queryType == "string") {
            query = stringifyQuery(queryObj.value);
        } else {
            query = queryObj.value;
        }
        if (service) {
            try {
                let res = await service.getList(query);
                if (res) {
                    let data = res.data.result;
                    if (data) {
                        if (data.data == undefined) {
                            lazyTable.value.data = [];
                        } else {
                            if (Array.isArray(data.data)) {
                                lazyTable.value.data = data.data || [];
                            } else {
                                lazyTable.value.detail = data.data;
                            }
                            if ("total_count" in data.page) {
                                lazyTable.value.pagination.total =
                                    data.page.total_count;
                            }
                        }
                    }
                    lazyTable.value.loading = false;
                }
            } catch (err: any) {
                if (err.code !== "ERR_CANCELED") {
                    lazyTable.value.loading = false;
                }
            }
        }
    };

    const remove = async (id: string | string[], ...rest: any) => {
        if (lazyTable.value.loading) {
            return;
        }
        lazyTable.value.loading = true;
        try {
            if (service?.remove) {
                let res = await service.remove(id, ...rest);
                refresh();
                // let ids: any;
                // if (!Array.isArray(id)) {
                //     ids = [id];
                // } else {
                //     ids = id;
                // }

                // for (let i = 0; i < lazyTable.value.data.length; ) {
                //     let item = lazyTable.value.data[i] as any;
                //     if (ids.includes(item.id)) {
                //         lazyTable.value.data.splice(i, 1);
                //     } else {
                //         i++;
                //     }
                // }
                // if (lazyTable.value.data.length == 0) {
                //     if (lazyTable.value.pagination.current > 1) {
                //         lazyTable.value.pagination.current -= 1;
                //         changePageIndex(lazyTable.value.pagination.current);
                //     } else {
                //         refresh();
                //     }
                // }
            }
        } catch (err) {
            console.log(err);
            refresh();
        } finally {
            lazyTable.value.loading = false;
        }
    };

    const filterObjUndefined = (obj: any = {}): {} => {
        return Object.fromEntries(
            Object.entries(obj).filter(([key, value]) => value !== undefined),
        );
    };

    const changePageIndex = (index: number) => {
        router.push({
            path: route.path,
            query: filterObjUndefined({
                ...route.query,
                ...{ current_page: index },
            }),
        });
    };
    const changePageItems = (size: number) => {
        router.push({
            path: route.path,
            query: filterObjUndefined({
                ...route.query,
                ...{ page_items: size },
            }),
        });
    };
    const search = () => {
        searchObjAddDateRange();
        router.push({
            path: route.path,
            query: filterObjUndefined({
                ...route.query,
                ...{ current_page: 1 },
                ...searchObj.value,
            }),
        });
    };

    const repalce = () => {
        searchObjAddDateRange();
        router.replace({
            path: route.path,
            query: filterObjUndefined({
                ...route.query,
                ...{ current_page: 1 },
                ...searchObj.value,
            }),
        });
    };
    const refresh = () => {
        router.replace({
            path: route.path,
            query: filterObjUndefined({
                ...route.query,
                t: Date.now(),
            }),
        });
    };

    const dateRange = ref();
    const resetSearchObj = (exclude: any[] = []) => {
        dateRange.value = "";
        let cloneObj = Object.assign({}, searchObj.value);

        for (let key in searchObj.value) {
            if (exclude.includes(key)) {
                continue;
            }
            searchObj.value[key] = undefined;
        }

        searchObj.value["current_page"] = 1;
        return cloneObj;
    };

    const getValueByType = (value: any, type: any) => {
        let res: any;
        switch (type) {
            case Object.prototype.toString.call(1):
                res = Number(value);
                break;
            case Object.prototype.toString.call(true):
                res = Boolean(value);
                break;
            case Object.prototype.toString.call([]):
                res = [value];
                break;
            case Object.prototype.toString.call({}):
                res = { [value]: value };
                break;
            default:
                res = value;
        }
        return res;
    };

    watch(
        () => [router.currentRoute.value.query, route.path],
        (newArr: any, oldArr: any) => {
            if (oldArr && newArr[1] != oldArr[1]) {
                return;
            }
            let newValue = newArr[0];
            queryObj.value = {};
            if (!customSearch) {
                const { current_page, page_items, ...rest } = newValue;
                lazyTable.value.pagination.current = current_page
                    ? Number(current_page)
                    : 1;
                lazyTable.value.pagination.pageSize = page_items
                    ? Number(page_items)
                    : lazyTable.value.pagination.pageSize;

                for (let key in rest) {
                    let typeKey = queryValueTypeMap[key];
                    let value = rest[key];
                    if (typeKey) {
                        if (
                            Object.prototype.toString.call(rest[key]) != typeKey
                        ) {
                            value = getValueByType(value, typeKey);
                        }
                    }

                    queryObj.value[key] = value;
                    searchObj.value[key] = value;
                }
            } else {
                customSearch(newValue);
            }
            getList();
        },
        {
            immediate,
        },
    );

    const handleTableChange = (
        page: { pageSize: number; current: number },
        filters: any,
        sorter: any,
    ) => {
        if (page.current != lazyTable.value.pagination.current) {
            changePageIndex(page.current);
        } else if (page.pageSize != lazyTable.value.pagination.pageSize) {
            changePageItems(page.pageSize);
        }
    };

    const hdlChangeStatus = async (
        id: any,
        checked: any,
        field: any = "status",
        vals: any[] = [true, false],
        isOnly = false,
        orgId?: number,
    ) => {
        if (lazyTable.value.loading) {
            return;
        }
        lazyTable.value.loading = true;
        try {
            if (checked == vals[0] && service?.enable) {
                let res = await service.enable(id, orgId, checked);
            } else if (checked == vals[1] && service?.disable) {
                let res = await service.disable(id, orgId, checked);
            }
            if (isOnly) {
                lazyTable.value.data.forEach((item: any) => {
                    if (item.id != id) {
                        item[field] = vals[1];
                    }
                });
            }
        } catch (err) {
            message.error("修改失败");
            refresh();
        } finally {
            lazyTable.value.loading = false;
        }
    };

    const hdlCancelChangeStatus = async (
        item: any,
        field = "status",
        vals: any[] = [true, false],
    ) => {
        if (item[field] == vals[0]) {
            item[field] = vals[1];
        } else {
            item[field] = vals[0];
        }
    };

    const getPopupContainer = (triggerNode: HTMLElement) => {
        return triggerNode;
    };

    const filterColums = (colums: any[], pickDataIndex: string[]) => {
        return colums
            .filter((item) => {
                if (pickDataIndex.includes(item.dataIndex || item.key)) {
                    return true;
                }
                return false;
            })
            .map((item) => {
                return {
                    name: item.title,
                    value: item.dataIndex || item.key,
                };
            });
    };

    let startTimeKey = dateRangeFieldNames && dateRangeFieldNames["startTime"];
    let endTimeKey = dateRangeFieldNames && dateRangeFieldNames["endTime"];
    const initDateRange = () => {
        const query = route.query;
        if (
            startTimeKey &&
            endTimeKey &&
            query[startTimeKey] &&
            query[endTimeKey]
        ) {
            dateRange.value = [
                dayjs(Number(query[startTimeKey])),
                dayjs(Number(query[endTimeKey])),
            ];
        }
    };
    const searchObjAddDateRange = () => {
        if (startTimeKey && endTimeKey) {
            if (dateRange.value) {
                searchObj["value"][startTimeKey] = dateRange.value[0].valueOf();
                searchObj["value"][endTimeKey] = dateRange.value[1].valueOf();
            } else {
                searchObj["value"][startTimeKey] = "";
                searchObj["value"][endTimeKey] = "";
            }
        }
    };

    return {
        lazyTable,
        queryObj,
        searchObj,
        remove,
        changePageIndex,
        changePageItems,
        search,
        repalce,
        handleTableChange,
        refresh,
        hdlChangeStatus,
        getPopupContainer,
        resetSearchObj,
        presets,
        filterColums,
        dateRange,
        initDateRange,
        searchObjAddDateRange,
        hdlCancelChangeStatus,
    };
}
